import { useContext, useMemo, useRef } from 'react';
import type { FiledContextProps } from './Context/FieldContext';
import FiledContext from './Context/FieldContext';
import ListContext, { ListContextProps } from './Context/ListContext';
import Field from './Field';
import type {
  InternalNamePath,
  ListField,
  ListOperations,
  ListProps,
  StoreValue,
} from './interface';
import { InternalFieldProps } from './interface/FieldEntityType';
import { arrayItemMove, nameToNamePath } from './utils/valueUtil';

function List<Values = any>(props: ListProps<Values>) {
  const parentListContext = useContext(ListContext);
  const fieldContext = useContext(FiledContext);
  const { name, initialValue, validateTrigger, rules, children, isListField } =
    props;

  const prefixName = useMemo(() => {
    const tempPrefixName = fieldContext.prefixName || [];
    return [...tempPrefixName, ...nameToNamePath(name)];
  }, [fieldContext.prefixName, name]);

  const listFieldContextValue = useMemo<FiledContextProps>(
    () => ({ ...fieldContext, prefixName }),
    [fieldContext, prefixName],
  );

  const keyRef = useRef<{ keys: number[]; id: number }>({
    keys: [], //keys的index对应List 的子级Field（Field.isList === false）的 namePath[prefixName.length]
    id: 0,
  });

  const keyManager = keyRef.current;

  const currentListContextValue = useMemo<ListContextProps>(
    () => ({
      getKey: (namePath: InternalNamePath) => {
        //['users',0, 'name']
        const prefixNaneLength = prefixName.length; //prefixName:['users'] 1
        const keyIndex = namePath[prefixNaneLength] as number; // 0
        return [
          keyManager.keys[keyIndex],
          namePath.slice(prefixNaneLength + 1),
        ]; // [0,['name']]
      },
    }),
    [prefixName, keyManager],
  );

  // source === 'internal': 说明是List下的Field--render() 不用刷新整个List
  const shouldUpdate: InternalFieldProps['shouldUpdate'] = (
    prevValue,
    nextValue,
    { source },
  ) => {
    if (source === 'internal') {
      return false;
    }
    return prevValue !== nextValue;
  };

  return (
    <ListContext.Provider value={currentListContextValue}>
      <FiledContext.Provider value={listFieldContextValue}>
        <Field
          name={[]}
          initialValue={initialValue}
          validateTrigger={validateTrigger}
          rules={rules}
          isListField={isListField ?? !!parentListContext}
          isList
          shouldUpdate={shouldUpdate}
        >
          {({ value = [], onChange }, meta) => {
            const { getFieldValue } = fieldContext;
            const getListValues = () => {
              //[{name,age}]
              const values = getFieldValue(prefixName || []) as StoreValue[];
              return values || [];
            };
            const operations: ListOperations = {
              add: (defaultValue = undefined, index) => {
                const currListValues = getListValues();
                if (
                  typeof index === 'number' &&
                  index >= 0 &&
                  index < currListValues.length
                ) {
                  keyManager.keys = [
                    ...keyManager.keys.slice(0, index),
                    keyManager.id,
                    ...keyManager.keys.slice(index),
                  ]; //slice >=  <
                  onChange([
                    ...currListValues.slice(0, index),
                    defaultValue,
                    ...currListValues.slice(index),
                  ]);
                } else {
                  keyManager.keys = [...keyManager.keys, keyManager.id];
                  onChange([...currListValues, defaultValue]);
                }
                keyManager.id += 1;
              },
              remove: (removeIndex) => {
                const currListValues = getListValues();
                const removeIndexSet = new Set(
                  Array.isArray(removeIndex) ? removeIndex : [removeIndex],
                );
                if (removeIndexSet.size <= 0) {
                  return;
                }
                keyManager.keys = keyManager.keys.filter(
                  (key, keysIndex) => !removeIndexSet.has(keysIndex),
                );
                onChange(
                  currListValues.filter(
                    (valueItem, valueIndex) => !removeIndexSet.has(valueIndex),
                  ),
                );
              },
              move: (from, to) => {
                const currListValues = getListValues();
                if (
                  from === to ||
                  from < 0 ||
                  from >= currListValues.length ||
                  to < 0 ||
                  to >= currListValues.length
                ) {
                  return;
                }
                keyManager.keys = arrayItemMove(currListValues, from, to);
                onChange(arrayItemMove(currListValues, from, to));
              },
            };

            const listValues: ListField[] = (
              Array.isArray(value) ? value : []
            ).map((valueItem, index) => {
              if (keyManager.keys[index] === undefined) {
                keyManager.keys[index] = keyManager.id;
                keyManager.id += 1;
              }
              return {
                name: index,
                key: keyManager.keys[index],
                isListField: true,
              };
            });

            return children(listValues, operations, meta);
          }}
        </Field>
      </FiledContext.Provider>
    </ListContext.Provider>
  );
}

export default List;
